package com.sf.ams.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sf.ams.entity.SystemInfo;
import com.sf.ams.exception.AmsException;
import com.sf.ams.saxhandler.DataStoreManager;

/**
 * 描述：修改 dataStore.xml中指定元素的数据
 * 
 * <pre>HISTORY
 * ****************************************************************************
 *  ID   DATE           PERSON          REASON
 *  1    2017年10月9日      Simba.Hua         Create
 * ****************************************************************************
 * </pre>
 * @author Simba.Hua
 */
public class XMLWriterUtil {
	private static Logger logger = LoggerFactory.getLogger(XMLWriterUtil.class);
	private static final Object o = new Object();
	private XMLWriterUtil(){
		
	}
	private static class Singleton {
		private static  XMLWriterUtil instance;
		static {
			instance  = new XMLWriterUtil();
		}
		public static XMLWriterUtil getInstance() {
			return instance;
		}
	}
	public static XMLWriterUtil getInstance(){
		return Singleton.getInstance();
	}
	/**
	 * 更新指定元素类型
	 * @param nodeExpress
	 * @param tagContent
	 */
	public  boolean updateXml(String nodeExpress,Map<String,String> tagContent){
		synchronized(o){
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		       final Element environment;
		       final Element root;
		        factory.setIgnoringElementContentWhitespace(true);
		        DocumentBuilder db;
				try {
					db = factory.newDocumentBuilder();
					 Document xmldoc = db.parse(DataStoreManager.getInstance().getDataStoreXml());
				     root = xmldoc.getDocumentElement();
				     environment = (Element) selectSingleNode(nodeExpress, root);
				     if (environment == null) {
				    	 throw new AmsException("未找到元素:" + nodeExpress);
				     }
				     tagContent.forEach((tagName,content) -> {
				    	 NodeList nodeList = environment.getElementsByTagName(tagName);
				    	 if (nodeList != null && nodeList.getLength() > 0){
				    		 nodeList.item(0).setTextContent(content);
				    	 }
				     });
				     logger.info("update XML path【{}】",nodeExpress);
				     return saveXml(DataStoreManager.getInstance().getDataStoreXmlPath(), xmldoc);
				} catch (ParserConfigurationException e) {
					logger.error("XMLWriterUtil updateXml ParserConfigurationException",e);
				} catch (SAXException e) {
					logger.error("XMLWriterUtil updateXml SAXException",e);
				} catch (IOException e) {
					logger.error("XMLWriterUtil updateXml IOException",e);
				}
		}
		return false;
	}
	/**
	 * 添加子元素到指定元素
	 * @param nodeExpress
	 * @param environments
	 */
	public   boolean addElements(String nodeExpress,List<Map<String,String>> environments,Integer maxIndex){
		synchronized(o){
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		       final Element environment;
		       final Element sysEnvironment;
		       final Element root;
		        factory.setIgnoringElementContentWhitespace(true);
		        DocumentBuilder db;
				try {
					db = factory.newDocumentBuilder();
					 Document xmldoc = db.parse(DataStoreManager.getInstance().getDataStoreXml());
				     root = xmldoc.getDocumentElement();
				     environment = (Element) selectSingleNode(nodeExpress + "']/environments", root);//找到environments元素
				     if (environment == null) {
				    	 throw new AmsException("未找到元素:" + nodeExpress);
				     }
				     sysEnvironment = (Element) selectSingleNode(nodeExpress + "']", root);//找到environments元素
				     NodeList nodeList = sysEnvironment.getElementsByTagName("maxIndex");
			    	 if (nodeList != null && nodeList.getLength() > 0){
			    		 nodeList.item(0).setTextContent(maxIndex.toString());
			    	 }
				     environments.forEach(e -> {
				    	 Element element = xmldoc.createElement("environment");
				    	 e.forEach((subElementName,content) -> {//生成每个environment的子元素
				    		 Element subElement = xmldoc.createElement(subElementName);
				    		 subElement.setTextContent(content);
				    		 element.appendChild(subElement);
				    	 });
				    	 environment.appendChild(element);
				     });
				     logger.info("add Elements to {}",nodeExpress + "']/environments");
				     return saveXml(DataStoreManager.getInstance().getDataStoreXmlPath(), xmldoc);
				} catch (ParserConfigurationException e) {
					logger.error("XMLWriterUtil addElements ParserConfigurationException",e);
				} catch (SAXException e) {
					logger.error("XMLWriterUtil addElements SAXException",e);
				} catch (IOException e) {
					logger.error("XMLWriterUtil addElements IOException",e);
				}
				return false;
		}
	}
	private  Node selectSingleNode(String express, Object source) {//查找节点，并返回第一个符合条件节点
        Node result=null;
        XPathFactory xpathFactory=XPathFactory.newInstance();
        XPath xpath=xpathFactory.newXPath();
        try {
            result=(Node) xpath.evaluate(express, source, XPathConstants.NODE);
        } catch (XPathExpressionException e) {
        	logger.error("XMLWriterUtil method selectSingleNode XPathExpressionException",e);
        }
        
        return result;
    }
	
	private  boolean saveXml(String fileName, Document doc) throws IOException {//将Document输出到文件
	        TransformerFactory transFactory = TransformerFactory.newInstance();
	        try {
	            Transformer transformer = transFactory.newTransformer();
	            transformer.setOutputProperty("indent", "yes");
	            DOMSource source=new DOMSource();
	            source.setNode(doc);
	            StreamResult result=new StreamResult();
	            result.setOutputStream(new FileOutputStream(new File(fileName)));
	            transformer.transform(source, result);
	            return true;
	        } catch (TransformerConfigurationException e) {
	        	logger.error("XMLWriterUtil method saveXml XPathExpressionException",e);
	        } catch (TransformerException e) {
	        	
	        	logger.error("XMLWriterUtil method saveXml TransformerException",e);
	        } catch (FileNotFoundException e) {
	        	logger.error("XMLWriterUtil method saveXml FileNotFoundException",e);
	        }  
	        return false;
	    }
	
	public  boolean addSystem(SystemInfo system){
		if(StringUtil.isEmpty(system.getSystemCode())){
			throw new AmsException("系统不能为空！");
		}
		synchronized(o){
			
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		        Element environment;
		        Element root;
		        factory.setIgnoringElementContentWhitespace(true);
		        DocumentBuilder db;
				try {
					db = factory.newDocumentBuilder();
					 Document xmldoc = db.parse(DataStoreManager.getInstance().getDataStoreXml());
				     root = xmldoc.getDocumentElement();
				     environment = (Element) selectSingleNode("/automaticSql/systems/system[systemCode='"+system.getSystemCode()+"']", root);
				     if (environment != null) {
				    	 throw new AmsException("系统【" + system.getSystemCode()+"】已经存在，请勿重复添加！");
				     }
				     environment = (Element) selectSingleNode("/automaticSql/systems", root);
				     Element systemElement = xmldoc.createElement("system");
				     Element systemCode = xmldoc.createElement("systemCode");
				     systemCode.setTextContent(system.getSystemCode());
				     Element pathType = xmldoc.createElement("pathType");
				     pathType.setTextContent(system.getPathType());
				     Element pathAddress = xmldoc.createElement("pathAddress");
				     pathAddress.setTextContent(system.getPathAddress());
				     Element gitUserName = xmldoc.createElement("gitUserName");
				     gitUserName.setTextContent(system.getGitUserName());
				     Element gitPassword = xmldoc.createElement("gitPassword");
				     gitPassword.setTextContent(AESUtil.AESEncode(system.getSystemCode(), system.getGitPassword()));
				     Element gitBranch = xmldoc.createElement("gitBranch");
				     gitBranch.setTextContent(system.getGitBranch());
				     Element sqlPath = xmldoc.createElement("sqlPath");
				     sqlPath.setTextContent(system.getSqlPath());
				     Element maxIndex = xmldoc.createElement("maxIndex");
				     maxIndex.setTextContent("0");
				     Element environments = xmldoc.createElement("environments");
				     systemElement.appendChild(systemCode);
				     systemElement.appendChild(pathType);
				     systemElement.appendChild(pathAddress);
				     systemElement.appendChild(gitUserName);
				     systemElement.appendChild(gitPassword);
				     systemElement.appendChild(gitBranch);
				     systemElement.appendChild(sqlPath);
				     systemElement.appendChild(maxIndex);
				     systemElement.appendChild(environments);
					 environment.appendChild(systemElement);
					 logger.info(" add system 【{}】",system.getSystemCode());
				     return saveXml(DataStoreManager.getInstance().getDataStoreXmlPath(), xmldoc);
				} catch (ParserConfigurationException e) {
					logger.error("XMLWriterUtil addSystem ParserConfigurationException",e);
				} catch (SAXException e) {
					logger.error("XMLWriterUtil addSystem SAXException",e);
				} catch (IOException e) {
					logger.error("XMLWriterUtil addSystem IOException",e);
				}
				return false;
		
		}
	}
	
	public  boolean  deleteElement(String parentElement,List<String> childrenElements) {
		if(StringUtil.isEmpty(parentElement) || childrenElements == null || childrenElements.isEmpty()) {
			throw new AmsException("删除的路径不存在");
		}
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	       final Element environment;
	       final Element root;
	        factory.setIgnoringElementContentWhitespace(true);
	        DocumentBuilder db;
			try {
				db = factory.newDocumentBuilder();
				 Document xmldoc = db.parse(DataStoreManager.getInstance().getDataStoreXml());
			     root = xmldoc.getDocumentElement();
			     environment = (Element) selectSingleNode(parentElement, root);//找到父节点
			     if (environment == null) {
			    	 throw new AmsException("删除的数据不存在" + parentElement);
			     }
			     childrenElements.forEach(child -> {
			    	 Element childElement = (Element) selectSingleNode(parentElement + child, root);
			    	 if (childElement != null) {
			    		 environment.removeChild(childElement);
			    	 }
			     });
			     logger.info("delete element from {}",parentElement);
			     return saveXml(DataStoreManager.getInstance().getDataStoreXmlPath(), xmldoc);
			} catch (ParserConfigurationException e) {
				logger.error("XMLWriterUtil deleteElement ParserConfigurationException",e);
			} catch (SAXException e) {
				logger.error("XMLWriterUtil deleteElement SAXException",e);
			} catch (IOException e) {
				logger.error("XMLWriterUtil deleteElement IOException",e);
			}
			return false;
	
	}
}
